#include "GraphicManager.h"
#include "assert.h"

// Initialize the Graphic Manager
void cGraphicManager::Init() {
	// Initializing the handle
	mHandle = GetStdHandle(STD_OUTPUT_HANDLE);

	// Initializing the back buffer
	memset(macBackBuffer, ' ', kuiConsoleArea);

	// Initializing the color buffer to black and white
	memset(macColorBuffer, 0x0F, kuiConsoleArea);
}

// Deinitialize the Graphic Manager
void cGraphicManager::DeInit() {
	// DeInitializing the back buffer
	memset(macBackBuffer, ' ', kuiConsoleArea);

	// DeInitializing the color buffer to black and white
	memset(macColorBuffer, 0x0F, kuiConsoleArea);
}

void cGraphicManager::WriteChar(unsigned luiX, unsigned luiY, char lChar) {
	assert(luiX < kuiConsoleDimX);
   assert(luiY < kuiConsoleDimY);
	unsigned luiIndex = luiX + luiY * kuiConsoleDimX;
	macBackBuffer[luiIndex] = lChar;
	macColorBuffer[luiIndex] = mcCurrentColour;
}
	
void cGraphicManager::WriteChars(unsigned luiX, unsigned luiY, const char* lacStr, unsigned luiLen) {
	unsigned luiIndex = luiX + luiY * kuiConsoleDimX;
	assert(luiIndex + luiLen < kuiConsoleArea);

	memcpy(&(macBackBuffer[luiIndex]), lacStr, luiLen);
	memset(&(macColorBuffer[luiIndex]), mcCurrentColour, luiLen); 
}
	
void cGraphicManager::WriteChars(unsigned luiX, unsigned luiY, const char* lacStr) {
	WriteChars(luiX,luiY, lacStr, strlen(lacStr));
}

void cGraphicManager::SetColor( eColor leFore, eColor leBack )
{
   unsigned char lcForeColor = (unsigned char)leFore;
   unsigned char lcBackColor = (unsigned char)leBack;
   lcBackColor <<= 4;
   mcCurrentColour = (lcForeColor | lcBackColor);
}

void cGraphicManager::SetForegroundColor( eColor leColor )
{
   // Make 0 the old forecolor
   unsigned char lcBackColor = (mcCurrentColour & 0xF0);
   unsigned char lcForeColor = (unsigned char)leColor;
   mcCurrentColour = ( lcBackColor | lcForeColor);
}

void cGraphicManager::SetBackgroundColor( eColor leColor )
{
   // Displace the color back color to the right position
   unsigned char lcBackColor = (unsigned char)leColor << 4;
   // Make 0 the old background color
   unsigned char lcForeColor = (mcCurrentColour & 0x0F);
   mcCurrentColour = ( lcBackColor | lcForeColor );
}

void cGraphicManager::SwapBuffer() {
	// Initialize the coordinates
	COORD lCoord = {0, 0};

	// Set the position
	SetConsoleCursorPosition(mHandle, lCoord);

	// lock the console
	LockWindowUpdate(GetConsoleWindow());

	// Prepare vars
	unsigned luiStart = 0;
	unsigned char lcColor = macColorBuffer[0];

	// For each character in the buffer
	for (unsigned luiIndex = 1; luiIndex < kuiConsoleArea; luiIndex++) {
		// If the color changed
		if (macColorBuffer[luiIndex] != lcColor) {
			// Set the color
			SetConsoleTextAttribute(mHandle, (WORD) lcColor);

			// Print the characteres
			DWORD liCount;
			int liCharacterCount	= luiIndex - luiStart;
			WriteConsole(mHandle, &(macBackBuffer[luiStart]), 
							liCharacterCount, &liCount, NULL);

			// Update Information
			luiStart = luiIndex;
			lcColor = macColorBuffer[luiIndex];
		}
	}

	// Set the color
	SetConsoleTextAttribute(mHandle, (WORD) lcColor);

	// Print the last chunk
	DWORD liCount;
	int liCharacterCount = kuiConsoleArea - luiStart;
	WriteConsole(mHandle, &(macBackBuffer[luiStart]), 
							liCharacterCount, &liCount, NULL);

	// Set the position
	SetConsoleCursorPosition(mHandle, lCoord);

	// Unlock The console
	LockWindowUpdate(NULL);
}

void cGraphicManager::ClearBuffer() {
	memset(macBackBuffer, ' ', kuiConsoleArea);
	memset(macColorBuffer, mcCurrentColour, kuiConsoleArea);
}

void cGraphicManager::ShowTheCursor(bool lbShow) {
	CONSOLE_CURSOR_INFO lCursor;
	if (GetConsoleCursorInfo(mHandle, &lCursor)) {
		lCursor.bVisible = lbShow;
		SetConsoleCursorInfo(mHandle, &lCursor);
	}
}